// **************************************************************
// Com ++ Framework by the C++ World
// Please report defects: mailto:compp@cplusplusworld.com
// Please visit: http://www.cplusplusworld.com/socketlibrary.html
// **************************************************************

#include <arpa/inet.h>
#include "ComPlusPlus/Comm.h"
#include "ComPlusPlus/SClnt.h"

#include "SysPlusPlus/Logger.h"
#include "SysPlusPlus/Tools.h"

#include "Sig.h"

compp::SClnt::SClnt( const std::string & IPAddr, const int port ) {

  S.SetOptNonBlocking();  
  S.Connect ( IPAddr, port);
  S.AttachFD();
  S.SetReadAhead ( true ); 

}

bool compp::SClnt::disConnect( ) {
  S.Shutdown();
  S.Close();
  return true;
}

bool compp::SClnt::Connect( const std::string & IPAddr, const int port ) {

  syspp::Logger *Log = syspp::Logger::Instance();
  Log->Info ( "SClnt : Connection attempt to %s:%d", IPAddr.c_str(), port );
  S.SetOptNonBlocking();  
  S.Connect ( IPAddr, port);
  S.AttachFD();
  S.SetReadAhead ( true ); 
  Log->Info ( "SClnt : Connection to %s:%d succeeded", IPAddr.c_str(), port );
  return true;
}

compp::SClnt::SClnt(  ) {


}

compp::SClnt::~SClnt( ) {

  S.Shutdown (0);

}

std::string compp::SClnt:: requestTransaction (  const std::string & request, const bool cyphered ) {

  syspp::Logger *Log = syspp::Logger::Instance();

  long Sec = htonl ( _COMM_SEC  );
  long Cyph = htonl ( _COMM_CYPH );

  int Len = htonl ( request.size() );
  char c[sizeof (int) ]; // Temporary
  std::string R = "";
  int LResponse;
  std::string retval;

//   std::cout << "1 " <<  request  <<  " " << cyphered << "\n" ;
  try {
    if ( cyphered ) {
      Log->Debug ( "SClnt cyphering." );
      memcpy ( (void*) c, (void*) &Cyph, sizeof (Cyph));
    } else {
      Log->Debug ( "SClnt pain." );
      memcpy ( (void*) c, (void*) &Sec, sizeof (Sec));
    }

    R.append ( c, sizeof ( Len ) );
    
    memcpy ( (void*) c, (void*) &Len, sizeof (Len));
    R.append ( c, sizeof ( Len ) );

    if ( cyphered ) {
      std::string cs = request;
      syspp::Tools::Enc (cs);
      //       std::cout << "CYPH " <<  request  <<  cs << "\n" ;
      R.append ( cs );
    } else {
      R.append ( request );

    }
//        std::cout << "1 " <<  R  << "\n" ;
    if ( S.Writen ( R) <= 0 ) {
      Log->Info ( "SClnt. Sending of request failed(%s).", strerror (errno) );
      throw syspp::ComException ( "Server does not accept comands." )  ;    
    }

    if ( S.Readn ( (char *) & LResponse, sizeof ( LResponse )) <= 0 ) {
      Log->Info ( "SClnt. Retrieving of response failed(%s).", strerror (errno) );
      throw syspp::ComException ( "Server does not respond.(1)" )  ;
    }
    

    LResponse = ntohl ( LResponse );
    if ( LResponse < 0 ) {
      Log->Info ( "SClnt. Response not valid." );
      throw syspp::ComException ( "Server response does not make any sense." )  ;    
    }

    if ( S.Readn ( retval, LResponse ) <= 0 ) {
      Log->Info ( "SClnt. Response not valid." );
      throw syspp::ComException ( "Server does not respond (2)." )  ;    
    }

  } catch ( syspp::ComException &e ) {
    std::string s = "Server Communication Exception : (" ;
    s += e.what () ;
    s += ")";
    Log->Info ( s.c_str() );
    throw  syspp::ComException ( s.c_str() )  ;    
  } catch ( ... ) {
    std::string s = "Server Communication Exception : (General)" ;
    Log->Info ( s.c_str() );
    throw syspp::ComException ( s.c_str()  ) ;
  }

  if ( cyphered ) {
    syspp::Tools::Dec (retval);
  }
  Log->Debug ( "SClnt: Response OK." );
//   std::cout << "Retval " << retval <<"\n";
  return retval;

}
